// Copyright 2011 and onwards Noam Shazeer and Georges Harik

// THIS FILE IS NOT BEING USED

#ifndef _INTSEQUENCES_PROBLEM_H_ 
#define _INTSEQUENCES_PROBLEM_H_

#include "interpret.h"
#include "graphdl.h"

struct SequenceSearch : public AllocatorDependant, public Tester {
  SequenceIndex index_;
  pthread_mutex_t lock_;
  pair<uint64, pair<int32, int32> > * code_seq_cache_;
  uint64 cache_size_;
  ofstream store_;
  GraphDL gdl_;
  int64 dl_;

  virtual int32 NumShards() { return 1; } 
  virtual void FlagReferences(int32 shard, Frontier * frontier);
  virtual void ObjectsDeleted(int32 shard);

  SequenceSearch();
  
  ~SequenceSearch() {
    delete [] code_seq_cache_;
  }

  struct SeqInfo {
  SeqInfo() : code_(NULL), original_dl_(0), correct_(false) {}
    Object * code_;
    uint64 original_dl_;
    bool correct_;
  };
  SeqInfo * seq_info_;
  
  uint64 num_correct_;
  uint64 num_predicted_;

  vector<bool> ever_matched_;
  uint64 new_matches_this_run_;

  // Handles changes to the gdl and utility_
  void CheckEverMatched(uint64 id) {
    if (!ever_matched_[id]) {
      cout << "New match id:" << id << endl;
      ever_matched_[id] = true;
      new_matches_this_run_++;
    }    
  }

  // Returns a difference in DL for a new solution
  int64 GuessDLDiff(uint64 id, Object * code) {
    int64 ret = 0;    
    OverlayDL odl(&gdl_);
    ret -= odl.dl_;
    SeqInfo & ref = seq_info_[id];
    if (ref.code_) odl.AddObject(ref.code_, -1);
    else ret -= ref.original_dl_;
    odl.AddObject(code, 1);
    ret += odl.dl_;
    if (odl.failed_) return 0.0;
    return ret;
  }

  void SetSeqInfo(uint64 id, Object * code, bool correct) {
    SeqInfo & ref = seq_info_[id];
    dl_ -= gdl_.dl_;
    if (ref.code_) {
      gdl_.AddObject(ref.code_, -1);
    } else {
      dl_ -= ref.original_dl_;
    }
    if (code) {
      gdl_.AddObject(code, 1);
    } else {
      dl_ += ref.original_dl_;
    }
    num_correct_ -= (ref.correct_ ? 1 : 0);
    num_predicted_ -= (ref.code_ ? 1 : 0);
    ref.code_ = code;
    ref.correct_ = correct;
    num_correct_ += (ref.correct_ ? 1 : 0);
    num_predicted_ += (ref.code_ ? 1 : 0);
    dl_ += gdl_.dl_;
  }
  
  uint64 NumSequences() { return index_.num_sequences_;}

  // Which sequence do you match, and is it correct
  pair<int32, int32> CodeToSequence(Object *& code, Vinterpreter *interp);

  // returns a new utility
  double Test(Object *&code, Vinterpreter *interp_, bool update);
  Object * Data(Object *&param, ThreadAllocator *a);

  int SequencesFound() { return num_predicted_; }

  string StoreFileName() { return "store/seq-code";}
  void LoadState(ThreadAllocator *ta);
};


// A functor that runs a function from integer to integer via interpretation
struct Interpret {
  Object ** code_;
  Vinterpreter *interp_;
  int64 operator () (int64 x) {
    Object * arg = MakeInteger(x);
    Object * call_code = interp_->a_->MakeArray(2, code_, &arg);
    ObjectSaver s_call_code(interp_->a_, &call_code);
    Object * result 
      = interp_->SafeExecute(call_code, (5000 * (x + 1)));
    if (result && GetType(result) == INTEGER) return GetInteger(result);
    // Return a useless number if there was a problem.
    return 0xDEADBEEF;
  }
};



#endif
